package com.tongtong.middleware.blockchain.client.web3j.contract;

import org.web3j.abi.FunctionReturnDecoder;
import org.web3j.abi.TypeReference;
import org.web3j.abi.datatypes.*;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class ContractDecoder {

    public static List<Type> decode(String types, String rawInput) {

        List<TypeReference<?>> typeList = getTypeList(types);
        return FunctionReturnDecoder.decode(rawInput, convert(typeList));
    }

    private static List<TypeReference<?>> getTypeList(String types) {
        List<TypeReference<?>> typeList = new ArrayList<>();

        for (String type : types.split(",")) {
            switch (type) {
                case "bool":
                    typeList.add(new TypeReference<Bool>() {});
                    break;
                case "uint256":
                case "uint128":
                case "uint64":
                case "uint32":
                case "uint8":
                    typeList.add(new TypeReference<Uint>() {});
                    break;
                case "int256":
                case "int128":
                case "int64":
                case "int32":
                case "int8":
                    typeList.add(new TypeReference<Int>() {});
                    break;
                case "address":
                    typeList.add(new TypeReference<Address>() {});
                    break;
                case "string":
                    typeList.add(new TypeReference<Utf8String>() {});
                    break;
                case "bytes":
                    typeList.add(new TypeReference<Bytes>() {});
                    break;
                default:

            }
        }

        return typeList;
    }

    @SuppressWarnings("unchecked")
    public static List<TypeReference<Type>> convert(List<TypeReference<?>> input) {
        List<TypeReference<Type>> result = new ArrayList<>(input.size());
        result.addAll(
                input.stream()
                        .map(typeReference -> (TypeReference<Type>) typeReference)
                        .collect(Collectors.toList()));
        return result;
    }
}